﻿// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. 
// See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Diagnostics.Tracing;
using System.Linq;
using System.Reactive.Subjects;
using System.Text;
using System.Threading.Tasks;

namespace System.Threading.Actors
{
    // Listens for ActorETWEventSource events, logs them to a ReplaySubject.
    public sealed class ActorETWEventListener : EventListener
    {
        // Event retention policy: Rx's ReplaySubject lets us store a maximum number of events
        // as well as keep a sliding window of events (ie keep only the last 3 days of events).
        // Here's where we set that policy.
        private const int EVENT_STORE_SIZE = 1000;
        private static readonly TimeSpan EVENT_STORE_WINDOW_LENGTH = TimeSpan.FromDays(3);

        private ReplaySubject<ActorEvent> m_subject;
        private string m_targetActorName;

        public ActorETWEventListener(string targetActorName)
        {
            m_subject = new ReplaySubject<ActorEvent>(EVENT_STORE_SIZE, EVENT_STORE_WINDOW_LENGTH);
            m_targetActorName = targetActorName;
        }

        public ISubject<ActorEvent> ActorEventSubject
        {
            get {return m_subject;}
        }

        protected override void OnEventWritten(EventWrittenEventArgs eventData)
        {
            // Convert to a type more palatable for JSON [de]serialization.
            var convertedEventData = ActorETWEventInfo.FromEventWrittenEventArgs(eventData, m_targetActorName);
            if (convertedEventData != null) // will be null on target actor or partition mismatch
            {
                // TODO: An ActorEvent constructor that allows for pre-JSON'd payload.  That way, we
                // could write a fast JSON serializer for payloads, instead of relying upon reflection.
                var actorEvent = ActorEvent.FromPayload("ETW", convertedEventData.PartitionName, convertedEventData, ActorETWEventInfo.ToJson);
                m_subject.OnNext(actorEvent);
            }
        }

        public override void Dispose()
        {
            m_subject.OnCompleted();
        }
    }
}
